using System.IO;
using System;
namespace VideoSearch
{
    /// <summary>    
    /// Reads the meta information embedded in an FLV file    
    /// </summary>
    public class FlvMetaDataReader
    {
        /// <summary>        
        /// Reads the meta information (if present) in an FLV        
        /// </summary>       
        /// <param name="path">The path to the FLV file</returns>        
        public static FlvMetaInfo GetFlvMetaInfo(string path)
        {
            if (!File.Exists(path))
            {
                throw new Exception(String.Format("File '{0}' doesn't exist for FlvMetaDataReader.GetFlvMetaInfo(path)", path));
            }
            bool hasMetaData = false;
            double duration = 0;
            double width = 0;
            double height = 0;
            double videoDataRate = 0;
            double audioDataRate = 0;
            Double frameRate = 0;
            DateTime creationDate = DateTime.MinValue;
            // open file           
            FileStream fileStream = new FileStream(path, FileMode.Open);
            try
            {
                // read where "onMetaData"                
                byte[] bytes = new byte[10];
                fileStream.Seek(27, SeekOrigin.Begin);
                int result = fileStream.Read(bytes, 0, 10);
                // if "onMetaData" exists then proceed to read the attributes         
                string onMetaData = ByteArrayToString(bytes);
                if (onMetaData == "onMetaData")
                {
                    hasMetaData = true;
                    // 16 bytes past "onMetaData" is the data for "duration"           
                    duration = GetNextDouble(fileStream, 16, 8);
                    // 8 bytes past "duration" is the data for "width"                
                    width = GetNextDouble(fileStream, 8, 8);
                    // 9 bytes past "width" is the data for "height"        
                    height = GetNextDouble(fileStream, 9, 8);
                    // 16 bytes past "height" is the data for "videoDataRate"          
                    videoDataRate = GetNextDouble(fileStream, 16, 8);
                    // 16 bytes past "videoDataRate" is the data for "audioDataRate"   
                    audioDataRate = GetNextDouble(fileStream, 16, 8);
                    // 12 bytes past "audioDataRate" is the data for "frameRate"     
                    frameRate = GetNextDouble(fileStream, 12, 8);
                    // read in bytes for creationDate manually     
                    fileStream.Seek(17, SeekOrigin.Current);
                    byte[] seekBytes = new byte[24];
                    result = fileStream.Read(seekBytes, 0, 24);
                    string dateString = ByteArrayToString(seekBytes);
                    // create .NET readable date string        
                    // cut off Day of Week   
                    dateString = dateString.Substring(4);
                    // grab 1) month and day, 2) year, 3) time      
                    dateString = dateString.Substring(0, 6) + " " + dateString.Substring(16, 4) + " " + dateString.Substring(7, 8);                    
                    // .NET 2.0 has DateTime.TryParse  
                    
                    try
                    {
                        creationDate = Convert.ToDateTime(dateString);
                    }
                    catch { }
                }
            }
            catch (Exception e)
            {
                // no error handling   
                
               
            }
            finally
            {
                fileStream.Close();
            }
            return new FlvMetaInfo(hasMetaData, duration, width, height, videoDataRate, audioDataRate, frameRate, creationDate);
        }
        private static Double GetNextDouble(FileStream fileStream, int offset, int length)
        {
            // move the desired number of places in the array        
            fileStream.Seek(offset, SeekOrigin.Current);            // create byte array            
            byte[] bytes = new byte[length];            // read bytes   
            int result = fileStream.Read(bytes, 0, length);
            // convert to double (all flass values are written in reverse order)    
            return ByteArrayToDouble(bytes, true);
        }
        private static string ByteArrayToString(byte[] bytes)
        {
            string byteString = string.Empty;
            foreach (byte b in bytes)
            {
                byteString += Convert.ToChar(b).ToString();
            } return byteString;
        }
        private static Double ByteArrayToDouble(byte[] bytes, bool readInReverse)
        {
            if (bytes.Length != 8) 
                throw new Exception("bytes must be exactly 8 in Length"); 
            if (readInReverse) 
                Array.Reverse(bytes); 
            return BitConverter.ToDouble(bytes, 0);
        }
    }
    /// <summary>    
    /// Read only container holding meta data embedded in FLV files    
    /// </summary>   
    public class FlvMetaInfo
    {
        private Double _duration;
        private Double _width;
        private Double _height;
        private Double _frameRate;
        private Double _videoDataRate;
        private Double _audioDataRate;
        private DateTime _creationDate;
        private bool _hasMetaData;
        /// <summary>       
        /// The duration in seconds of the video        
        /// </summary>        
        public Double Duration
        {
            get { return _duration; }
            //set { _duration = value; }      
        }
        /// <summary>      
        /// The width in pixels of the video       
        /// </summary>        
        public Double Width
        {
            get { return _width; }
            //set { _width = value; }       
        }        /// <summary>       
        /// The height in pixels of the video       
        /// </summary>        
        public Double Height
        {
            get { return _height; }
            //set { _height = value; }       
        }
        /// <summary>       
        /// The data rate in KB/sec of the video         
        /// </summary>        
        public Double VideoDataRate
        {
            get { return _videoDataRate; }
            //set { _videoDataRate = value; }    
        }
        /// <summary>        
        /// The data rate in KB/sec of the video's audio track        
        /// </summary>        
        public Double AudioDataRate
        {
            get { return _audioDataRate; }
            //set { _audioDataRate = value; }        
        }
        /// <summary>        
        /// The frame rate of the video        
        /// </summary>        
        public Double FrameRate
        {
            get { return _frameRate; }
            //set { _frameRate = value; }       
        }
        /// <summary>       
        /// The creation date of the video       
        /// </summary>        
        public DateTime CreationDate
        {
            get { return _creationDate; }
            //set { _creationDate = value; }        
        }
        /// <summary>       
        /// Whether or not the FLV has meta data       
        /// </summary>       
        public bool HasMetaData
        {
            get { return _hasMetaData; }
            //set { _hasMetaData = value; }        
        }
        internal FlvMetaInfo(bool hasMetaData, Double duration, Double width, Double height, Double videoDataRate, Double audioDataRate, Double frameRate, DateTime creationDate)
        {
            _hasMetaData = hasMetaData;
            _duration = duration;
            _width = width;
            _height = height;
            _videoDataRate = videoDataRate;
            _audioDataRate = audioDataRate;
            _frameRate = frameRate;
            _creationDate = creationDate;
        }
    }
}